Partial Hydration를 통한 웹 성능 최적화
2026-01-26
Page Router (Next 12)의 Hydration 방식
Page Router(Next 12)에서는 렌더링과 하이드레이션이 비교적 단순한 흐름으로 이루어진다.
서버에서는 getServerSideProps 또는 getStaticProps가 실행되고, 그 결과를 기반으로 React Tree 전체를 HTML로 렌더링한다.
이후 브라우저에 HTML이 전달되면, 페이지를 구성하는 모든 컴포넌트에 대해 하이드레이션이 수행된다.
이 과정에서 이벤트 핸들러, 상태, 이펙트가 모두 활성화되며 결과적으로 페이지 전체가 클라이언트에서 실행 가능한 React 애플리케이션이 된다.
문제는 페이지 대부분이 정적인 콘텐츠일 경우에도, 단 하나의 버튼이나 인터랙션을 위해 페이지 전체가 하이드레이션된다는 점이다.
지나치게 무거운 Over Hydration
이 방식은 규모가 커질수록 점점 부담이 된다.
Page Router 환경에서는 하이드레이션을 위해 현재 페이지를 구성하는 모든 자바스크립트 번들이 브라우저로 전송된다. 그 결과 자바스크립트 파일의 크기와 개수가 함께 증가하고, 네트워크 비용과 파싱 비용 역시 자연스럽게 커진다.
특히 본질적인 문제는 다음 지점에 있다.
이미 SSR 단계에서 완전히 렌더링된 DOM임에도, 실제로는 자바스크립트 동작이 전혀 필요 없는 요소들까지 하이드레이션 대상에 포함된다는 점이다.
즉, “보여주기만 하면 되는 영역”조차 React 코드 실행과 Hydration 비용을 함께 떠안게 된다.
Over Hydration을 예시
아래는 Next.js로 구현된 웹 페이지 예시다.

SSR이 수행되면 브라우저에는 우선 자바스크립트가 제거된 상태의 HTML 문서가 전달된다. 이 시점의 화면은 정상적으로 보이지만, 아직 어떠한 상호작용도 불가능한 상태다.
이후 Next.js는 현재 화면을 구성하는 모든 DOM 요소에 대응하는 React 자바스크립트 코드를 로드한 뒤 페이지 전체에 대해 하이드레이션을 수행한다. (이 자바스크립트 코드는 리액트로 작성된 컴포넌트를 빌드하고 번들링한 결과물이다.)
하지만 실제로 이 페이지를 자세히 보면, 자바스크립트가 반드시 필요한 영역은 사용자 인터랙션이 발생하는 두 개의 버튼뿐이다.
그 외의 영역은 이미 SSR 단계에서 렌더링이 끝났고, 상태 변경이나 이벤트 처리가 필요 없는 정적인 콘텐츠다. 즉, 자바스크립트도 필요 없고 하이드레이션을 거칠 이유도 없는 영역들이다.
그럼에도 Page Router에서는 페이지 전체가 하이드레이션되면서 불필요한 Long Task와 JS 실행 비용이 발생하게 된다.
“부분 하이드레이션”을 통한 웹 성능 최적화
만약 실제로 하이드레이션이 필요한 영역에 대해서만 필요한 자바스크립트 코드만 내려받고, 그 영역만 부분적으로 Hydration을 수행할 수 있다면 어떨까?
불필요한 자바스크립트 실행을 크게 줄일 수 있고, 초기 로딩 성능과 런타임 성능 모두 개선될 것이다.
이 문제를 구조적으로 해결한 것이 App Router의 Partial Hydration이다.
Partial Hydration과 App Router

App Router는 단순히 “Partial Hydration 기능을 추가했다”기보다는, 처음부터 Partial Hydration이 가능하도록 설계된 구조라고 보는 편이 맞다.
왜 App Router = Partial Hydration일까?
Server Component가 기본값이기 때문이다.
Server Component는 왜 중요한가
use client 지시자가 없는 컴포넌트는 기본적으로 Server Component다. Server Component는 서버에서 HTML로 렌더링될 뿐, 자바스크립트 번들이 브라우저로 전달되지 않는다. 따라서 하이드레이션 대상 자체가 아니다.
// Server Component (기본)
export default function Page() {
return <StaticContent />;
}이 구조 자체가 “필요한 부분만 하이드레이션하겠다”는 Partial Hydration의 전제를 자연스럽게 만든다.
Client Component만 하이드레이션된다
반대로 use client가 선언된 컴포넌트는 Client Component로 분류된다. 이 컴포넌트와 그 하위 서브트리만 자바스크립트가 내려받아지고 하이드레이션이 수행된다.
'use client';
export function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
{count}
</button>
);
}
// Server Component
import { Counter } from './Counter';
export default function Page() {
return (
<>
<StaticContent /> // 하이드레이션 없음
<Counter /> // 하이드레이션 발생
</>
);
}결과적으로 페이지 전체가 아니라 정말 필요한 조각만 하이드레이션된다.
마치며
Page Router의 구조적 한계와 Over Hydration 문제를 통해, Next.js가 App Router 아키텍처로 전환한 이유를 Partial Hydration 관점에서 살펴보았다.